﻿#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//6.堆内存的成员，手动申请，手动释放；
int* getSpace()
{
	int* p = (int*)malloc(sizeof(int) * 5);
	if (NULL == p)
	{
		return NULL;
	}
	//2.j++的效率要低于++j；因为j++是先赋值再加，j=j+1,要产生临时变量，内存开销大，所以效率低；
	int j = 0;
	j++;//等同于j=j+1;
	++j;

	//1.只要是连续的内存空间，都能使用下标的方式访问内存；
	//p[0] = 100;
	//for (int i = 0; i < 5; i++)
	for (int i = 0; i < 5; ++i)
	{
		p[i] = 100 + i;
	}
	return p;
}
//7.定义变量的时候，一定要初始化，很多的bug产生，都是由于没有初始化造成的；
void allocateSpace(char* p)
{
	p = malloc(100);
	memset(p, 0, 100);
	strcpy(p, "hello world!");
}
//10.现在char*p的地址是存在于栈中，方法结束就释放了。传给alllocatStackSpace()不是char*的指针变量，而是char**类型的
//二级指针变量，是一个地址值。其实传char*和传char**都一样，都是传地址，只是char*的地址直接指向字符串，而char**的
//地址指向char*的地址，当调用的方法结束后，栈区的地址都会被回收。不同的是，char**的变量p，最后改变的不是地址，而
//*p的值，这个不属于栈区，整个调用方法的过程中，也没有参与操作，参与操作一直是**p的地址，最后释放的也是**p的地址；
//**p的地址指向*p，*p的地址指向p，p的地址指向字符串；
void allocateStackSpace(char** p)
{
	char* temp = malloc(100);
	memset(temp, 0, 100);
	strcpy(temp, "hello world!");

	*p = temp;
}
void testHeap()
{
	int* ret = getSpace();
	for (int i = 0; i < 5; ++i)
	{
		printf("3.输出int*类型指针ret指向，指针p开辟的堆内存空间的值：%d\n", ret[i]);//100,101,...,104
	}
	//4.使用完毕堆内存，一定要释放堆内存；
	free(ret);
	//5.将指针ret的地址指向NULL，是为了防止程序还会使用到ret变量，再次free会宕机，而free(NULL)不会宕机；
	ret = NULL;

	char* pA = NULL;
	allocateSpace(pA);
	//9.此时pA指向的值为NULL，原因是allocateSpace()方法，确实让pA在栈中拿到了“hello world!”的地址，可是方法结束，
	//栈中的内存就释放了，自然pA的地址为NULL了。pA的地址为NULL后，指向的值也就不确定了。而堆内存中的“hello world!”
	//由于未被释放，就发生内存泄漏，同时也没有地址指向这块内存了；
	printf("8.通过allocateSpace()方法，给char*类型指针变量pA开辟堆内存，并赋值，则pA指向的值为：%s\n", pA);//NULL

	allocateStackSpace(&pA);
	printf("11.pA的地址会在方法结束时，被栈区内存释放掉。那现在让pA的地址指向temp，则pA指向的值为：%s\n", pA);//hello world!
}

//main182：堆区内存管理
int main182()
{
	testHeap();

	system("pause");
	return EXIT_SUCCESS;
}